import * as THREE from 'three';
import { Debug } from './Debug';

/**
 * 音效类型枚举
 */
export enum SoundType {
  BACKGROUND = 'background',
  EFFECT = 'effect',
  UI = 'ui'
}

/**
 * 音效管理器 - 负责加载、播放和管理游戏中的所有音效
 */
export class AudioManager {
  private static instance: AudioManager;
  private listener: THREE.AudioListener;
  private sounds: Map<string, THREE.Audio | THREE.PositionalAudio>;
  private audioLoader: THREE.AudioLoader;
  private loadingManager: THREE.LoadingManager;
  private masterVolume: number = 1.0;
  private volumeSettings: { [key in SoundType]: number } = {
    [SoundType.BACKGROUND]: 0.5,
    [SoundType.EFFECT]: 0.8,
    [SoundType.UI]: 0.7
  };
  private muted: boolean = false;
  private camera: THREE.Camera | null = null;

  /**
   * 获取AudioManager单例
   */
  public static getInstance(loadingManager?: THREE.LoadingManager): AudioManager {
    if (!AudioManager.instance) {
      AudioManager.instance = new AudioManager(loadingManager);
    }
    return AudioManager.instance;
  }

  /**
   * 私有构造函数，创建音效管理器
   */
  private constructor(loadingManager?: THREE.LoadingManager) {
    this.listener = new THREE.AudioListener();
    this.sounds = new Map();
    this.loadingManager = loadingManager || new THREE.LoadingManager();
    this.audioLoader = new THREE.AudioLoader(this.loadingManager);
    
    Debug.log('音效系统初始化完成');
    
    // 检查是否支持Web Audio API
    if (!window.AudioContext && !window.webkitAudioContext) {
      Debug.warn('当前浏览器不支持Web Audio API，音效功能将不可用');
    }
    
    // 从本地存储中加载音量设置
    this.loadVolumeSettings();
  }

  /**
   * 设置相机 - 音频监听器将附加到相机上
   */
  public setCamera(camera: THREE.Camera): void {
    this.camera = camera;
    camera.add(this.listener);
    Debug.log('音频监听器已附加到相机');
  }

  /**
   * 预加载音效资源
   * @param url 音效文件路径
   * @param id 音效ID
   * @param type 音效类型
   * @param onLoad 加载完成回调
   */
  public preload(url: string, id: string, type: SoundType = SoundType.EFFECT, onLoad?: () => void): void {
    Debug.log(`预加载音效: ${id} (${url})`);
    
    this.audioLoader.load(
      url,
      (buffer) => {
        // 创建音频对象但不播放
        const audio = new THREE.Audio(this.listener);
        audio.setBuffer(buffer);
        audio.setVolume(this.getTypeVolume(type));
        audio.setLoop(type === SoundType.BACKGROUND);
        
        // 存储音频对象以便后续使用
        this.sounds.set(id, audio);
        
        Debug.log(`音效加载完成: ${id}`);
        if (onLoad) onLoad();
      },
      (xhr) => {
        const percent = (xhr.loaded / xhr.total) * 100;
        Debug.log(`音效加载进度 ${id}: ${Math.round(percent)}%`);
      },
      (error) => {
        Debug.error(`音效加载失败 ${id}: ${error}`);
      }
    );
  }

  /**
   * 预加载3D位置音效资源
   * @param url 音效文件路径
   * @param id 音效ID
   * @param type 音效类型
   * @param onLoad 加载完成回调
   */
  public preloadPositional(url: string, id: string, type: SoundType = SoundType.EFFECT, onLoad?: () => void): void {
    Debug.log(`预加载3D位置音效: ${id} (${url})`);
    
    this.audioLoader.load(
      url,
      (buffer) => {
        // 创建3D位置音频对象但不播放
        const audio = new THREE.PositionalAudio(this.listener);
        audio.setBuffer(buffer);
        audio.setVolume(this.getTypeVolume(type));
        audio.setRefDistance(5); // 参考距离
        audio.setRolloffFactor(1); // 衰减因子
        audio.setDistanceModel('linear'); // 距离模型
        audio.setDirectionalCone(180, 230, 0.5); // 方向性圆锥体
        
        // 存储音频对象以便后续使用
        this.sounds.set(id, audio);
        
        Debug.log(`3D位置音效加载完成: ${id}`);
        if (onLoad) onLoad();
      },
      (xhr) => {
        const percent = (xhr.loaded / xhr.total) * 100;
        Debug.log(`3D位置音效加载进度 ${id}: ${Math.round(percent)}%`);
      },
      (error) => {
        Debug.error(`3D位置音效加载失败 ${id}: ${error}`);
      }
    );
  }

  /**
   * 播放音效
   * @param id 音效ID
   * @param volume 音量覆盖（可选）
   * @returns 是否成功播放
   */
  public play(id: string, volume?: number): boolean {
    const sound = this.sounds.get(id);
    
    if (!sound) {
      Debug.warn(`尝试播放未加载的音效: ${id}`);
      return false;
    }
    
    if (this.muted) {
      Debug.log(`音效已静音，不播放: ${id}`);
      return false;
    }
    
    try {
      // 如果音效已经在播放，先停止
      if (sound.isPlaying) {
        sound.stop();
      }
      
      // 设置音量（如果提供）
      if (volume !== undefined) {
        sound.setVolume(volume);
      }
      
      sound.play();
      Debug.log(`播放音效: ${id}`);
      return true;
    } catch (error) {
      Debug.error(`播放音效时出错 ${id}: ${error}`);
      return false;
    }
  }

  /**
   * 在3D空间中播放位置音效
   * @param id 音效ID
   * @param position 3D位置
   * @param object 附加到的3D对象（可选）
   * @param volume 音量覆盖（可选）
   * @returns 是否成功播放
   */
  public playAt(id: string, position: THREE.Vector3, object?: THREE.Object3D, volume?: number): boolean {
    const sound = this.sounds.get(id);
    
    if (!sound || !(sound instanceof THREE.PositionalAudio)) {
      Debug.warn(`尝试播放未加载的3D位置音效或音效不是位置音效: ${id}`);
      return false;
    }
    
    if (this.muted) {
      Debug.log(`音效已静音，不播放: ${id}`);
      return false;
    }
    
    try {
      // 如果音效已经在播放，先停止
      if (sound.isPlaying) {
        sound.stop();
      }
      
      // 设置音量（如果提供）
      if (volume !== undefined) {
        sound.setVolume(volume);
      }
      
      // 如果提供了对象，将音效附加到该对象
      if (object) {
        object.add(sound);
      } else {
        // 创建临时对象在特定位置播放
        const tempObject = new THREE.Object3D();
        tempObject.position.copy(position);
        tempObject.add(sound);
        
        // 添加到场景并在播放完成后移除
        if (this.camera && this.camera.parent) {
          this.camera.parent.add(tempObject);
          
          const duration = (sound.buffer?.duration || 0) * 1000;
          setTimeout(() => {
            this.camera?.parent?.remove(tempObject);
          }, duration + 100); // 延迟一点以确保声音完全播放
        }
      }
      
      sound.play();
      Debug.log(`播放3D位置音效: ${id} 在位置 (${position.x.toFixed(2)}, ${position.y.toFixed(2)}, ${position.z.toFixed(2)})`);
      return true;
    } catch (error) {
      Debug.error(`播放3D位置音效时出错 ${id}: ${error}`);
      return false;
    }
  }

  /**
   * 停止播放音效
   * @param id 音效ID
   * @returns 是否成功停止
   */
  public stop(id: string): boolean {
    const sound = this.sounds.get(id);
    
    if (!sound) {
      Debug.warn(`尝试停止未加载的音效: ${id}`);
      return false;
    }
    
    if (sound.isPlaying) {
      sound.stop();
      Debug.log(`停止音效: ${id}`);
      return true;
    }
    
    return false;
  }

  /**
   * 停止所有音效
   */
  public stopAll(): void {
    this.sounds.forEach((sound, id) => {
      if (sound.isPlaying) {
        sound.stop();
        Debug.log(`停止音效: ${id}`);
      }
    });
  }

  /**
   * 暂停所有音效
   */
  public pauseAll(): void {
    this.sounds.forEach((sound) => {
      if (sound.isPlaying) {
        sound.pause();
      }
    });
    Debug.log('暂停所有音效');
  }

  /**
   * 恢复所有音效
   */
  public resumeAll(): void {
    if (!this.muted) {
      this.sounds.forEach((sound) => {
        if (sound.source && !sound.isPlaying) {
          sound.play();
        }
      });
      Debug.log('恢复所有音效');
    }
  }

  /**
   * 设置音效循环播放
   * @param id 音效ID
   * @param loop 是否循环
   */
  public setLoop(id: string, loop: boolean): void {
    const sound = this.sounds.get(id);
    if (sound) {
      sound.setLoop(loop);
    }
  }

  /**
   * 设置主音量
   * @param volume 音量值（0-1）
   */
  public setMasterVolume(volume: number): void {
    this.masterVolume = Math.max(0, Math.min(1, volume));
    
    // 更新所有音效的音量
    this.updateAllVolumes();
    
    // 保存设置到本地存储
    this.saveVolumeSettings();
    
    Debug.log(`设置主音量: ${this.masterVolume.toFixed(2)}`);
  }

  /**
   * 设置指定类型的音量
   * @param type 音效类型
   * @param volume 音量值（0-1）
   */
  public setTypeVolume(type: SoundType, volume: number): void {
    this.volumeSettings[type] = Math.max(0, Math.min(1, volume));
    
    // 更新所有音效的音量
    this.updateAllVolumes();
    
    // 保存设置到本地存储
    this.saveVolumeSettings();
    
    Debug.log(`设置${type}音量: ${this.volumeSettings[type].toFixed(2)}`);
  }

  /**
   * 获取主音量
   * @returns 主音量值
   */
  public getMasterVolume(): number {
    return this.masterVolume;
  }

  /**
   * 获取指定类型的实际音量（考虑主音量）
   * @param type 音效类型
   * @returns 实际音量值
   */
  public getTypeVolume(type: SoundType): number {
    return this.volumeSettings[type] * this.masterVolume;
  }

  /**
   * 设置静音状态
   * @param muted 是否静音
   */
  public setMuted(muted: boolean): void {
    this.muted = muted;
    
    if (muted) {
      this.stopAll();
    }
    
    // 保存设置到本地存储
    localStorage.setItem('sound_muted', muted ? 'true' : 'false');
    
    Debug.log(`音效静音状态: ${muted}`);
  }

  /**
   * 获取静音状态
   * @returns 是否静音
   */
  public isMuted(): boolean {
    return this.muted;
  }

  /**
   * 切换静音状态
   * @returns 新的静音状态
   */
  public toggleMute(): boolean {
    this.setMuted(!this.muted);
    return this.muted;
  }

  /**
   * 释放资源
   */
  public dispose(): void {
    // 停止所有音效并释放资源
    this.stopAll();
    this.sounds.forEach((sound, id) => {
      sound.disconnect();
    });
    
    this.sounds.clear();
    
    if (this.camera) {
      this.camera.remove(this.listener);
    }
    
    Debug.log('音效系统资源已释放');
  }

  /**
   * 更新所有音效的音量
   * @private
   */
  private updateAllVolumes(): void {
    this.sounds.forEach((sound, id) => {
      // 不同类型的声音有不同的音量设置
      // 这里根据ID前缀猜测声音类型
      let type = SoundType.EFFECT;
      
      if (id.startsWith('bg_') || id.startsWith('background_')) {
        type = SoundType.BACKGROUND;
      } else if (id.startsWith('ui_') || id.startsWith('menu_')) {
        type = SoundType.UI;
      }
      
      sound.setVolume(this.getTypeVolume(type));
    });
  }

  /**
   * 保存音量设置到本地存储
   * @private
   */
  private saveVolumeSettings(): void {
    localStorage.setItem('sound_master_volume', this.masterVolume.toString());
    localStorage.setItem('sound_bg_volume', this.volumeSettings[SoundType.BACKGROUND].toString());
    localStorage.setItem('sound_effect_volume', this.volumeSettings[SoundType.EFFECT].toString());
    localStorage.setItem('sound_ui_volume', this.volumeSettings[SoundType.UI].toString());
  }

  /**
   * 从本地存储加载音量设置
   * @private
   */
  private loadVolumeSettings(): void {
    const masterVolume = localStorage.getItem('sound_master_volume');
    const bgVolume = localStorage.getItem('sound_bg_volume');
    const effectVolume = localStorage.getItem('sound_effect_volume');
    const uiVolume = localStorage.getItem('sound_ui_volume');
    const muted = localStorage.getItem('sound_muted');
    
    if (masterVolume) this.masterVolume = parseFloat(masterVolume);
    if (bgVolume) this.volumeSettings[SoundType.BACKGROUND] = parseFloat(bgVolume);
    if (effectVolume) this.volumeSettings[SoundType.EFFECT] = parseFloat(effectVolume);
    if (uiVolume) this.volumeSettings[SoundType.UI] = parseFloat(uiVolume);
    if (muted) this.muted = muted === 'true';
    
    Debug.log('从本地存储加载音效设置');
  }
} 